package meshToSolid;

import java.util.ArrayList;
import java.util.Vector;

import simpleGeom.Bounds3D;
import simpleGeom.Box3D;
import simpleGeom.Face3D;
import simpleGeom.HasBounds3D;

import simpleGeom.SegPreCalc;
import simpleGeom.TrianglePreCalc;

import simpleGeom.Vec2D;

public class ContainerGrid {

	public Container[][][] grid;
	float x1;
	float y1;
	float z1;
	float x2;
	float y2;
	float z2;
	float dim;
	float diag;
	public int nX;
	public int nY;
	public int nZ;

	float xFloat(int x){
		return  x * dim+x1;
	}
	float yFloat(int y){
		return y * dim+y1;
	}
	float zFloat(int z){
		return z * dim+z1;
	}
	int xInt(float x) {
		return (int) ((x - x1) / dim);
	}
	int yInt(float y) {
		return (int) ((y - y1) / dim);
	}
	int zInt(float z) {
		return (int) ((z - z1) / dim);
	}
	public ContainerGrid(Box3D b3d, float  dim) {
		x1 = b3d.getX1();
		y1 = b3d.getY1();
		z1 = b3d.getZ1();
		x2 = b3d.getX2();
		y2 = b3d.getY2();
		z2 = b3d.getZ2();
		nX = (int)(b3d.getDimX() / dim)+1;
		nY = (int)(b3d.getDimY() / dim)+1;
		nZ = (int)(b3d.getDimZ() / dim)+1;
		grid = new Container[nX][nY][nZ];
		this.dim=dim;
		this.diag=(float)(dim*Math.sqrt(3)*0.5f);
		for (int x = 0; x < nX; x++) {
			for (int y = 0; y < nY; y++) {
				for (int z = 0; z < nZ; z++) {
					/*Container container = new Container();
					container.x1 = x * dim+x1;
					container.y1 = y * dim+y1;
					container.z1 = z * dim+z1;
					container.x2 = (x + 1) * dim+x1;
					container.y2 = (y + 1) * dim+y1;
					container.z2 = (z + 1) * dim+z1;
					grid[x][y][z]=container;*/
				}
			}
		}
	}
	
	public Container get(int x,int y,int z){
		return grid[x][y][z];
	}
	public Container addContainer(int x,int y,int z){
		Container container = new Container();
		
		grid[x][y][z]=container;
		return container;
	}
	public void addObject(HasBounds3D object,float iso) {
		Box3D b = object.getBounds3D();
		b=b.getOffsetBox(iso);
		addObject(b,object);
	}
	
	public void addObject(Box3D b,Object object) {
		int x1 = xInt(b.getX1());
		int y1 = yInt(b.getY1());
		int z1 = zInt(b.getZ1());
		int x2 = xInt(b.getX2())+2;
		int y2 = yInt(b.getY2())+2;
		int z2 = zInt(b.getZ2())+2;
		x1=Math.max(x1,0);
		y1=Math.max(y1,0);
		z1=Math.max(z1,0);
		x2=Math.min(x2,nX-1);
		y2=Math.min(y2,nY-1);
		z2=Math.min(z2,nZ-1);
		for (int x = x1; x < x2; x++) {
			for (int y = y1; y < y2; y++) {
				for (int z = z1; z < z2; z++) {
					Container box =grid[x][y][z];
					if (box==null){
						box=new Container();
						grid[x][y][z]=box;
					}
					box.addObject(object);
				}
			}
		}
	}

	public void addObject(HasBounds3D object) {
		Box3D b = object.getBounds3D();
		addObject(b,object);
	}
	
	public void addObject(HasBounds3D object,TrianglePreCalc tri) {
		Box3D b = object.getBounds3D();
		int x1 = xInt(b.getX1());
		int y1 = yInt(b.getY1());
		int z1 = zInt(b.getZ1());
		int x2 = xInt(b.getX2())+2;
		int y2 = yInt(b.getY2())+2;
		int z2 = zInt(b.getZ2())+2;
		x1=Math.max(x1,0);
		y1=Math.max(y1,0);
		z1=Math.max(z1,0);
		x2=Math.min(x2,nX-1);
		y2=Math.min(y2,nY-1);
		z2=Math.min(z2,nZ-1);
		for (int x = x1; x < x2; x++) {
			for (int y = y1; y < y2; y++) {
				for (int z = z1; z < z2; z++) {
					float xF=xFloat(x);
					float yF=yFloat(y);
					float zF=zFloat(z);
					if (tri.getDistancePlane(xF,yF,zF)<diag){
						Container box =grid[x][y][z];
						if (box==null){
							box=new Container();
							grid[x][y][z]=box;
						}
						box.addObject(object);
					}
				}
			}
		}
	}

	
	public boolean isInside(int x, int y, int z){
		if (x < 0)
			return false;
		if (y < 0)
			return false;
		if (z < 0)
			return false;
		if (x > grid.length - 1)
			return false;
		if (y > grid[x].length - 1)
			return false;
		if (z > grid[x][y].length - 1)
			return false;
		return true;
	}
	
	public Vector<Object> getObjects(Box3D b,SegPreCalc seg) {
		Vector<Object> objects = new Vector<Object>();
		int xC1 = xInt(b.getX1());
		int yC1 = yInt(b.getY1());
		int zC1 = zInt(b.getZ1());
		int xC2 = xInt(b.getX2()) + 2;
		int yC2 = yInt(b.getY2()) + 2;
		int zC2 = zInt(b.getZ2()) + 2;
		
		xC1=Math.max(xC1,0);
		yC1=Math.max(yC1,0);
		zC1=Math.max(zC1,0);
		xC2=Math.min(xC2,nX-1);
		yC2=Math.min(yC2,nY-1);
		zC2=Math.min(zC2,nZ-1);
		
		for (int x = xC1; x < xC2; x++) {
			for (int y = yC1; y < yC2; y++) {
				for (int z = zC1; z < zC2; z++) {
					float xF = xFloat(x);
					float yF = yFloat(y);
					float zF = zFloat(z);
					Container box = grid[x][y][z];
					if (box != null) {
						if (seg.dist_Point_to_Line(xF, yF, zF) < diag) {
							for (int i = 0; i < box.objects.size(); i++) {
								Face3D object = (Face3D) box.objects.get(i);
								if (object.getId() != -1000) {
									objects.add(object);
									object.setId(-1000);
								}
							}
						}
					}
				}
			}
		}
		
		for(int i=0;i<objects.size();i++){
			Face3D object=(Face3D) objects.get(i);
			object.setId(0);
		}
		return objects;
	}
	public Vector<Object> getObjects(Box3D b) {
		Vector<Object> objects = new Vector<Object>();
		int xC1 = xInt(b.getX1());
		int yC1 = yInt(b.getY1());
		int zC1 = zInt(b.getZ1());
		int xC2 = xInt(b.getX2()) + 2;
		int yC2 = yInt(b.getY2()) + 2;
		int zC2 = zInt(b.getZ2()) + 2;
		
		xC1=Math.max(xC1,0);
		yC1=Math.max(yC1,0);
		zC1=Math.max(zC1,0);
		xC2=Math.min(xC2,nX-1);
		yC2=Math.min(yC2,nY-1);
		zC2=Math.min(zC2,nZ-1);
		for (int x = xC1; x < xC2; x++) {
			for (int y = yC1; y < yC2; y++) {
				for (int z = zC1; z < zC2; z++) {
					Container box = grid[x][y][z];
					if (box != null) {
						for (int i = 0; i < box.objects.size(); i++) {
							Face3D object = (Face3D) box.objects.get(i);
							if (object.getId() != -1000) {
								objects.add(object);
								object.setId(-1000);
							}
						}
					}
				}
			}
		}
		for(int i=0;i<objects.size();i++){
			Face3D object=(Face3D) objects.get(i);
			object.setId(0);
		}
		return objects;
	}

	public class Container {

		public ArrayList<Object> objects = new ArrayList<Object>();

		public void addObject(Object object) {
			objects.add(object);
		}
	}
}
